package org.zxp.gc.reference;

import java.lang.ref.WeakReference;

/**
 * @program: effectiveJava
 * @description: ${description}
 * @author: X-Pacific zhang
 * @create: 2019-05-20 11:44
 **/
public class TestWeakReference {
    public static void main(String[] args) throws InterruptedException {
        //这样有强引用存在，不可以回收，除非把apple设置为null
//        Apple apple = new Apple("1");
//        WeakReference<Apple> weakReference = new WeakReference<>(apple);
//        这样遇到GC就回收了
//        WeakReference<Apple> weakReference = new WeakReference<>(new Apple("1"));
//        try {
//            Thread.sleep(2000L);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        System.out.println(weakReference.get());
//        /**
//         * 在垃圾回收器线程扫描它所管辖的内存区域的过程中，一旦发现了只具有弱引用的对象，
//         * 不管当前内存空间足够与否，都会回收它的内存。不过，
//         * 由于垃圾回收器是一个优先级很低的线程，因此不一定会很快发现那些只具有弱引用的对象。
//         */
//        System.gc();//遇到gc就回收了
//        System.out.println(weakReference.get());


        //解释一下为什么ThreadLocal中Entry中的keyThreadLocal用WeakReference 有什么不一样的
//        Local local = new Local();//为了能在控制台看到这个类被回收
//        local.set("当前线程名称："+Thread.currentThread().getName());//将ThreadLocal作为key放入threadLocals.Entry中
//        Thread t = Thread.currentThread();//注意此时的threadLocals.Entry数组刚设置的referent是指向Local的，referent就是Entry中的key只是被WeakReference包装了一下
//        local = null;//断开强引用，即断开local与referent的关联，但Entry中此时的referent还是指向Local的，为什么会这样，当引用传递设置为null时无法影响传递内的结果
//        System.gc();//执行GC
//        t = Thread.currentThread();//这时Entry中referent是null了，被GC掉了，因为Entry的key是WeakReference，所以在没有强引用，只有一个弱引用，发生GC就被GC了
//        //如果这里不采用WeakReference，即使local=null，那么也不会回收Entry的key，因为Entry和key是强关联
        //但是这里仅能做到回收key不能回收value，如果这个线程运行时间非常长，即使referentGC了，value持续不清空，就有内存溢出的风险
        // 彻底回收最好调用remove
//        System.out.println(local);

        //remove验证
//        Local local = new Local();//为了能在控制台看到这个类被回收
//        local.set("当前线程名称："+Thread.currentThread().getName());//将ThreadLocal作为key放入threadLocals.Entry中
//        Thread t = Thread.currentThread();//注意此时的threadLocals.Entry数组刚设置的referent是指向Local的，referent就是Entry中的key只是被WeakReference包装了一下
//        local.remove();//remove了彻底回收，把map里的这个元素干掉了，并没有把自己干掉
////        local = null;//如果不加这句，local还需要等这个方法执行完了才能回收
//        System.gc();//执行GC
//        t = Thread.currentThread();//这时Entry中referent是null了，被GC掉了，因为Entry的key是WeakReference，所以在没有强引用，只有一个弱引用，发生GC就被GC了
//        //如果这里不采用WeakReference，即使local=null，那么也不会回收Entry的key，因为Entry和key是强关联
//        System.out.println(local);

        //线程执行完毕呢？
//        Thread thread = new Thread(() -> {
//            Local local = new Local();
//            Thread.currentThread();
//            local.set("inner");
//        });
//        thread.start();
//        Thread.sleep(1000);
//        int a = 0;//线程执行完毕后，threadLocal会自动释放是null，线程执行中threadLocal有值，但是线程池会重复用Thread，所以就不一定了

        //所以用完最好remove一下


        //对象直接=null和用WeakReference有什么区别，反正都是GC后回收
        //=null以后你就不能操作这个对象了
        //WeakReference在GC前都可以操作对象
    }
}
class Local extends ThreadLocal{
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("Local：finalize。");
    }
}
